package dijjer.io.xfer.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dijjer.util.AbstractThread;
import dijjer.util.logging.Logger;

public class HTTPRequestHandler extends AbstractThread {

	public static final String VERSION = "$Id: HTTPRequestHandler.java 2 2008-03-21 14:33:03Z ian.clarke $";

	private final Socket _sock;
	private final String _charSet = "UTF-8";

	public HTTPRequestHandler(Socket sock) {
		_sock = sock;
	}

	protected boolean loop() throws InterruptedException {
		OutputStream out = null;
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(_sock.getInputStream()));
			out = _sock.getOutputStream();

			try {

				String line = getHeader(reader).trim();
				String method = line.substring(0, line.indexOf(' '));
				String url = getURL(line);
				PageHandler handler = PageHandler.getHandler(method, url);
				HTTPResponse response = handler.handleRequest(method, url, getQueryParams(line), getHeaders(reader), reader);
				response.write(out);

				reader.close();
				out.close();
				_sock.close();
			} catch (HTTPException ex) {
				new HTTPExceptionResponse(ex).write(out);
			}
		} catch (Throwable e) {
			try {
				e.printStackTrace(); //temporary
				new HTTPExceptionResponse(e).write(out);
				out.close();
				_sock.close();
			} catch (Throwable ex) {
				ex.printStackTrace();
				throw new RuntimeException(ex.fillInStackTrace());
			}
		}
		if (!_sock.isClosed()) {
			try {
				_sock.close();
			} catch (IOException e) {
				Logger.error(e);
			}
		}
		return false;
	}

	protected void cleanUp() {
		throw new RuntimeException("Not Implemented Yet!!!");
	}

	private Map getHeaders(BufferedReader reader) throws IOException
	{
		Map headers = new HashMap();
		String line = null;
		while ((line = reader.readLine()) != null && !"".equals(line.trim())) {
			String[] header = line.split(":", 2);
			String name = header[0].trim();
			List params = new ArrayList();
			if (header.length == 2) {
			    String[] p = header[1].split(",");
				for (int i = 0; i < p.length; i++) {
					params.add(p[i].trim());
				}
			}
			headers.put(name, params);
		}
		return headers;
	}

	private String getURL(String line) {
		int end = line.indexOf(" HTTP/1.");
		return line.substring(line.indexOf(' ') + 1, end);
	}

	private Map getQueryParams(String line) throws UnsupportedEncodingException {
		Map paramMap = new HashMap();
		if (line.indexOf('?') == -1) {
			return paramMap;
		}
		String params = line.substring(line.indexOf('?') + 1, line.toUpperCase().lastIndexOf(" HTTP/1.")).trim();
		String[] pairs = params.split("\\&");
		for (int i = 0; i < pairs.length; i++) {
			String[] keyValue = pairs[i].split("\\=");
			String key = URLDecoder.decode(keyValue[0], _charSet);
			String value = null;
			if (keyValue.length > 1) {
				value = URLDecoder.decode(keyValue[1], _charSet);
			}
			if (paramMap.get(key) == null) {
				paramMap.put(key, new ArrayList());
			}
			((List)paramMap.get(key)).add(value);
		}
		return paramMap;
	}

	private String getHeader(BufferedReader reader) throws IOException {
		String line = reader.readLine();
		Logger.debug("REQUEST = " + line);

		if (line.equals("") || line.equals(HTTPServer.CRLF) || line.toLowerCase().indexOf("favicon.ico") >= 0) {
			throw new HTTPException(HttpURLConnection.HTTP_BAD_REQUEST, "Bad Request", line);
		}
		return line;
	}

}
